package com.example.rbacmanage.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.example.rbacmanage.common.enums.EnvEnum;
import com.example.rbacmanage.common.enums.FormTypeEnum;
import com.example.rbacmanage.common.enums.JavaTypeEnum;
import com.example.rbacmanage.common.enums.QueryTypeEnum;
import com.example.rbacmanage.converter.CodegenConverter;
import com.example.rbacmanage.entity.GenConfig;
import com.example.rbacmanage.entity.GenFieldConfig;
import com.example.rbacmanage.exception.MyException;
import com.example.rbacmanage.mapper.DatabaseMapper;
import com.example.rbacmanage.mapper.GenConfigMapper;
import com.example.rbacmanage.mapper.GenFieldConfigMapper;
import com.example.rbacmanage.property.CodegenProperty;
import com.example.rbacmanage.service.GenConfigService;
import com.example.rbacmanage.service.GenFieldConfigService;
import com.example.rbacmanage.vo.ColumnMetaData;
import com.example.rbacmanage.vo.GenConfigForm;
import com.example.rbacmanage.vo.TableMetaData;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class GenConfigServiceImpl implements GenConfigService {
    @Autowired
    private DatabaseMapper databaseMapper;
    @Autowired
    private CodegenProperty codegenProperty;
    @Autowired
    private GenConfigMapper genConfigMapper;
    @Autowired
    private GenFieldConfigService genFieldConfigService;
    @Autowired
    private CodegenConverter codegenConverter;
    @Value("${spring.profiles.active}")
    private String springProfilesActive;
    @Autowired
    private GenFieldConfigMapper genFieldConfigMapper;

    @Override
    public void save(GenConfig genConfig) {
        genConfig.setCreateTime(new Date());
        genConfigMapper.insert(genConfig);
    }

    @Override
    public void remove(Long[] ids) {
        for (Long id : ids) {
            genConfigMapper.del(id);
        }
    }

    @Override
    public void update(GenConfig genConfig) {
        genConfigMapper.update(genConfig);
    }

    @Override
    public List<GenConfig> getAll(GenConfig genConfig) {
        return genConfigMapper.list(genConfig);
    }

    @Override
    public PageInfo<GenConfig> getPage(GenConfig genConfig) {
        PageHelper.startPage(genConfig.getPage(), genConfig.getLimit());
        return new PageInfo<>(getAll(genConfig));
    }

    @Override
    public GenConfig getById(Long id) {
        return genConfigMapper.queryOneById(id);
    }

    @Override
    public Integer getCount(GenConfig genConfig) {
        return genConfigMapper.count(genConfig);
    }

    @Override
    public void checkRepeat(GenConfig genConfig) throws MyException {

    }

    @Override
    public GenConfigForm getGenConfigFormData(String tableName) {
        // 查询表生成配置
        GenConfig genConfig =  genConfigMapper.getByTableNameLimitOne(tableName);

        // 是否有代码生成配置
        boolean hasGenConfig = genConfig != null;

        // 如果没有代码生成配置，则根据表的元数据生成默认配置
        if (genConfig == null) {
            TableMetaData tableMetadata = databaseMapper.getTableMetadata(tableName);
            Assert.isTrue(tableMetadata != null, "未找到表元数据");

            genConfig = new GenConfig();
            genConfig.setTableName(tableName);

            String tableComment = tableMetadata.getTableComment();
            if (StrUtil.isNotBlank(tableComment)) {
                genConfig.setBusinessName(tableComment.replace("表", "").trim());
            }
            // 实体类名 = 表名去掉前缀后转驼峰，前缀默认为下划线分割的第一个元素
            String entityName;
            if (!tableName.contains("_")){
                entityName = StrUtil.toCamelCase(tableName);
            }else{
                entityName = StrUtil.toCamelCase(StrUtil.removePrefix(tableName, tableName.split("_")[0]));
            }
            genConfig.setEntityName(entityName);

            genConfig.setPackageName("com.example.rbacmanage");
            genConfig.setModuleName(codegenProperty.getDefaultConfig().getModuleName()); // 默认模块名
            genConfig.setAuthor(codegenProperty.getDefaultConfig().getAuthor());
        }

        // 根据表的列 + 已经存在的字段生成配置 得到 组合后的字段生成配置
        List<GenFieldConfig> genFieldConfigs = new ArrayList<>();

        // 获取表的列
        List<ColumnMetaData> tableColumns = databaseMapper.getTableColumns(tableName);
        if (CollectionUtil.isNotEmpty(tableColumns)) {
            // 查询字段生成配置
            GenFieldConfig genFieldConfig = new GenFieldConfig();
            genFieldConfig.setConfigId(genConfig.getId());
            List<GenFieldConfig> fieldConfigList = genFieldConfigService.getAll(genFieldConfig);
            Integer maxSort = fieldConfigList.stream()
                    .map(GenFieldConfig::getFieldSort)
                    .filter(Objects::nonNull) // 过滤掉空值
                    .max(Integer::compareTo)
                    .orElse(0);
            for (ColumnMetaData tableColumn : tableColumns) {
                // 根据列名获取字段生成配置
                String columnName = tableColumn.getColumnName();
                GenFieldConfig fieldConfig = fieldConfigList.stream()
                        .filter(item -> StrUtil.equals(item.getColumnName(), columnName))
                        .findFirst()
                        .orElseGet(() -> createDefaultFieldConfig(tableColumn));
                if (fieldConfig.getFieldSort() == null) {
                    fieldConfig.setFieldSort(++maxSort);
                }
                // 根据列类型设置字段类型
                String fieldType = fieldConfig.getFieldType();
                if (StrUtil.isBlank(fieldType)) {
                    String javaType = JavaTypeEnum.getJavaTypeByColumnType(fieldConfig.getColumnType());
                    fieldConfig.setFieldType(javaType);
                }
                // 如果没有代码生成配置，则默认展示在列表和表单
                if (!hasGenConfig) {
                    fieldConfig.setIsShowInList(1);
                    fieldConfig.setIsShowInForm(1);
                }
                genFieldConfigs.add(fieldConfig);
            }
        }
        // 对 genFieldConfigs 按照 fieldSort 排序
        genFieldConfigs = genFieldConfigs.stream().sorted(Comparator.comparing(GenFieldConfig::getFieldSort)).toList();
        GenConfigForm genConfigForm = codegenConverter.toGenConfigForm(genConfig, genFieldConfigs);

        genConfigForm.setFrontendAppName(codegenProperty.getFrontendAppName());
        genConfigForm.setBackendAppName(codegenProperty.getBackendAppName());
        return genConfigForm;
    }

    /**
     * 创建默认字段配置
     *
     * @param columnMetaData 表字段元数据
     * @return
     */
    private GenFieldConfig createDefaultFieldConfig(ColumnMetaData columnMetaData) {
        GenFieldConfig fieldConfig = new GenFieldConfig();
        fieldConfig.setColumnName(columnMetaData.getColumnName());
        fieldConfig.setColumnType(columnMetaData.getDataType());
        fieldConfig.setFieldComment(columnMetaData.getColumnComment());
        fieldConfig.setFieldName(StrUtil.toCamelCase(columnMetaData.getColumnName()));
        fieldConfig.setIsRequired("YES".equals(columnMetaData.getIsNullable()) ? 1 : 0);

        if (fieldConfig.getColumnType().equals("date")) {
            fieldConfig.setFormType(FormTypeEnum.DATE.getValue());
        } else if (fieldConfig.getColumnType().equals("datetime")) {
            fieldConfig.setFormType(FormTypeEnum.DATE_TIME.getValue());
        } else {
            fieldConfig.setFormType(FormTypeEnum.INPUT.getValue());
        }

        fieldConfig.setQueryType(QueryTypeEnum.EQ.getValue());
        fieldConfig.setMaxLength(columnMetaData.getCharacterMaximumLength());
        return fieldConfig;
    }

    @Override
    public void saveGenConfig(GenConfigForm formData) throws MyException {
        GenConfig genConfig = codegenConverter.toGenConfig(formData);
        GenConfig exist = genConfigMapper.getByTableNameLimitOne(genConfig.getTableName());
        if (exist != null) {
            genConfig.setId(exist.getId());
            genConfigMapper.update(genConfig);
        }else{
            genConfigMapper.insert(genConfig);
        }


        // 如果选择上级菜单且当前环境不是生产环境，则保存菜单
        Long parentMenuId = formData.getParentMenuId();
        if (parentMenuId != null && !EnvEnum.PROD.getValue().equals(springProfilesActive)) {
//            menuService.addMenuForCodegen(parentMenuId, genConfig);
        }

        List<GenFieldConfig> genFieldConfigs = codegenConverter.toGenFieldConfig(formData.getFieldConfigs());

        if (CollectionUtil.isEmpty(genFieldConfigs)) {
            throw new MyException("字段配置不能为空", HttpStatus.INTERNAL_SERVER_ERROR.value());
        }
        genFieldConfigs.forEach(genFieldConfig -> {

            for (GenConfigForm.FieldConfig config :formData.getFieldConfigs()){
                if (config.getColumnName().equals(genFieldConfig.getColumnName()) && config.getDictType() != null){
                    genFieldConfig.setDictType(config.getDictType());
                    break;
                }
            }

            genFieldConfig.setConfigId(genConfig.getId());

            GenFieldConfig existGenFieldConfig = genFieldConfigMapper.queryOneById(genFieldConfig.getId());
            if (existGenFieldConfig != null) {
                genFieldConfig.setId(existGenFieldConfig.getId());
                genFieldConfigMapper.update(genFieldConfig);
            }else{
                genFieldConfigMapper.insert(genFieldConfig);
            }
        });
    }

    @Override
    public void deleteGenConfig(String tableName) {
        GenConfig genConfig = genConfigMapper.getByTableNameLimitOne(tableName);
        boolean result = genConfigMapper.delByTableName(tableName);
        if (result) {
            genFieldConfigService.removeByConfigId(genConfig.getId());
        }
    }

    @Override
    public GenConfig getByTableName(String tableName) {
        return genConfigMapper.getByTableNameLimitOne(tableName);
    }
}
